package com.xrui.hbase.codec.impl;

import com.google.common.base.Preconditions;
import com.moz.kiji.delegation.Lookups;
import com.xrui.hbase.DecodedCell;
import com.xrui.hbase.codec.CellDecoder;
import com.xrui.hbase.impl.BoundColumnReaderSpec;
import com.xrui.hbase.schema.SchemaType;
import com.xrui.hbase.schema.TableLayout;
import com.xrui.hbase.schema.impl.CustomCellSchema;
import com.xrui.hbase.schema.spec.CellSpec;
import com.xrui.hbase.schema.spec.ColumnReaderSpec;


import java.io.IOException;

/**
 * De-serializes an HBase cell encoded.
 *
 * <p>
 * A Custom cell decoder is specific to one column in a DatabaseTable.
 * Custom encoder and decoder classes know how to encode and decode themselves.
 * <p>
 *
 * @param <T> The type of the decoded cell data.
 */
public final class CustomCellDecoder<T> implements CellDecoder<T> {

    /**
     * Cell decoder used for decoding.
     */
    private final CellDecoder mCellDecoder;

    /**
     * Initializes a CustomCellDecoder.
     *
     * @param cellSpec Specification of the cell encoding.
     */
    public CustomCellDecoder(CellSpec cellSpec) {
        Preconditions.checkNotNull(cellSpec);
        Preconditions.checkArgument(
            cellSpec.getCellSchema().getType() == SchemaType.CUSTOM);
        CustomCellSchema cellSchema = (CustomCellSchema) cellSpec.getCellSchema();
        mCellDecoder = Lookups.getNamed(CellDecoder.class).lookup(cellSchema.getCellDecoder());
    }

    /**
     * Initializes a CustomCellDecoder.
     *
     * @param layout TableLayout from which to create the cell decoder.
     * @param spec   Specification of the cell encoding.
     * @throws IOException on I/O error.
     */
    public CustomCellDecoder(TableLayout layout, BoundColumnReaderSpec spec)
        throws IOException {
        Preconditions.checkNotNull(layout);
        Preconditions.checkNotNull(spec);
        Preconditions.checkArgument(
            spec.getColumnReaderSpec().getEncoding() == ColumnReaderSpec.Encoding.CUSTOM);
        CustomCellSchema cellSchema = (CustomCellSchema) layout.getCellSchema(spec.getColumnName());
        mCellDecoder = Lookups.getNamed(CellDecoder.class).lookup(cellSchema.getCellDecoder());
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @SuppressWarnings("unchecked")
    public DecodedCell<T> decodeCell(byte[] encodedBytes) throws IOException {
        return mCellDecoder.decodeCell(encodedBytes);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public T decodeValue(byte[] bytes) throws IOException {
        return decodeCell(bytes).getData();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String getName() {
        return CustomCellDecoder.class.getName();
    }
}
